/*
 * CaseFuzzy.cpp
 *
 *  Created on: Jan 30, 2012
 *      Author: godinho
 */

#include <controller/CaseFuzzy.h>

#include <fuzzylite/FuzzyEngine.h>
#include <fuzzylite/LinguisticVariable.h>
#include <fuzzylite/ShoulderTerm.h>
#include <fuzzylite/TriangularTerm.h>
#include <fuzzylite/MamdaniRule.h>

#include <stdio.h>

#define MATRIX_CELL_MAX_LEN 10
#define NUM_ANTECEDENTS 5

char antecedents[NUM_ANTECEDENTS][MATRIX_CELL_MAX_LEN] =
                              {"TINY", "SMALL", "NORMAL", "BIG", "HUGE"};

char consequents[NUM_ANTECEDENTS][NUM_ANTECEDENTS][MATRIX_CELL_MAX_LEN] =
                             {{"MEAN_INC",  "SMALL_INC", "SMALL_INC",  "SMALL_DEC", "MEAN_DEC"},
                              {"MEAN_INC",  "SMALL_INC", "NONE",       "SMALL_DEC", "MEAN_DEC"},
                              {"SMALL_INC", "SMALL_INC", "NONE",       "SMALL_DEC", "MEAN_DEC"},
                              {"SMALL_INC", "NONE",      "NONE",       "SMALL_DEC", "MEAN_DEC"},
                              {"NONE",      "NONE",      "SMALL_DEC",  "MEAN_DEC",  "MEAN_DEC"}};

CaseFuzzy* CaseFuzzy::mInstance = 0;

CaseFuzzy::CaseFuzzy() {
    mEngine = new fl::FuzzyEngine();

    mQueue = new fl::InputLVar("Queue");
    initQueueTerms(mQueue);
    mEngine->addInputLVar(mQueue);


    initExtensionTerms();


    mRuleBloc = new fl::RuleBlock();
    initRules();
}

CaseFuzzy::~CaseFuzzy() {
    // TODO Auto-generated destructor stub
}

int CaseFuzzy::fuzzyfyQueue(int size) {
    return 0;
}

int CaseFuzzy::desfuzzyfyExtension(int extension) {

    switch(extension) {
    case 0:
        return -12;
        break;
    case 1:
        return -8;
        break;
    case 2:
        return -4;
        break;
    case 3:
        return 0;
        break;
    case 4:
        return 4;
        break;
    case 5:
        return 8;
        break;
    case 6:
        return 12;
        break;
    }
}

void CaseFuzzy::initRules() {
    char rule[200];
    for(int x = 0; x < NUM_ANTECEDENTS; x++) {
        for(int y = 0; y < NUM_ANTECEDENTS; y++) {
            sprintf(rule, "if SideQueue is %s and NextQueue is %s then Extension is %s",
                    antecedents[x], antecedents[y], consequents[x][y]);
            mRuleBloc->addRule(new fl::MamdaniRule(rule, *mEngine));
        }
    }
}

void CaseFuzzy::initQueueTerms(fl::LinguisticVariable* queueLinguisticVar) {
    queueLinguisticVar->addTerm(new fl::ShoulderTerm("TINY", 3, 6, true));
    queueLinguisticVar->addTerm(new fl::TriangularTerm("SMALL", 3, 9));
    queueLinguisticVar->addTerm(new fl::TriangularTerm("NORMAL", 6, 12));
    queueLinguisticVar->addTerm(new fl::TriangularTerm("BIG", 9, 15));
    queueLinguisticVar->addTerm(new fl::ShoulderTerm("HUGE", 12, 15, false));
}

void CaseFuzzy::initExtensionTerms() {

    mExtension = new fl::OutputLVar("Extension");

    fl::LinguisticTerm* bigDec   = new fl::ShoulderTerm("BIG_DEC", -12, -8, true);
    fl::LinguisticTerm* meanDec  = new fl::TriangularTerm("MEAN_DEC", -12, -4);
    fl::LinguisticTerm* smallDec = new fl::TriangularTerm("SMALL_DEC", -8, 0);
    fl::LinguisticTerm* none     = new fl::TriangularTerm("NONE", -4, 4);
    fl::LinguisticTerm* smallInc = new fl::TriangularTerm("SMALL_INC", 0, 8);
    fl::LinguisticTerm* meanInc  = new fl::TriangularTerm("MEAN_INC", 4, 12);
    fl::LinguisticTerm* bigInc   = new fl::ShoulderTerm("BIG_INC", 8, 12, false);

    mExtension->addTerm(bigDec);
    mExtension->addTerm(meanDec);
    mExtension->addTerm(smallDec);
    mExtension->addTerm(none);
    mExtension->addTerm(smallInc);
    mExtension->addTerm(meanInc);
    mExtension->addTerm(bigInc);

    mEngine->addOutputLVar(mExtension);
}

CaseFuzzy* CaseFuzzy::getInstance() {

    if(mInstance == 0) {
        mInstance = new CaseFuzzy();
    }

    return mInstance;

}

